package com.momoauth.common.security.aspect;

import com.momoauth.common.security.annotation.RequiresRoles;
import com.momoauth.common.security.dao.RoleDao;
import com.momoauth.common.core.exception.GlobalException;
import com.momoauth.common.security.entity.Role;
import com.momoauth.common.security.utils.JwtUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@Aspect
@Order(1)
public class RequiresRolesAspect {

    @Resource
    RoleDao roleDao;

    /**
     * 拦截方法进行角色权限判断
     * @param joinPoint
     */
    @Before("@annotation(com.momoauth.common.security.annotation.RequiresRoles)")
    public void Interceptor(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RequiresRoles requiresRoles = method.getAnnotation(RequiresRoles.class);
        // 判断是否拥有角色权限
        if (!handleUserRoles(requiresRoles)) {
            throw new GlobalException(50001,"很抱歉，角色权限不足。");
        }
    }

    /**
     * 角色权限判断处理
     * @param requiresRoles
     * @return
     */
    private boolean handleUserRoles(RequiresRoles requiresRoles) {
        // 值为空时返回错误信息
        if (requiresRoles.value().length == 0) {
            throw new GlobalException(50000,"@RequiresRoles注解内请填写合法的值。");
        }
        HttpServletRequest request = currentRequest();
        String token = request.getHeader("Authorization");
        // 从头部Token解析出用户ID
        Long userId = Long.parseLong(JwtUtil.getClaimName(token, "userId"));
        List<String> list = new ArrayList<>();
        // 根据用户ID取出该用户拥有的角色列表
        List<Role> allRoleList = roleDao.getRoleNameList(userId);
        // 查询不到任何角色信息时直接抛出错误
        if (allRoleList.size() == 0) {
            throw new GlobalException(50001,"该用户不拥有任何角色。");
        }
        // 把角色名称取出来丢进另一个List
        for (Role role : allRoleList) {
            list.add(role.getRoleName());
        }
        String[] roleList = list.toArray(new String[list.size()]);
        // 根据枚举常量判断结果是否吻合
        switch (requiresRoles.logical()) {
            case OR:
                for (String roleName : requiresRoles.value()) {
                    if (Arrays.asList(roleList).contains(roleName)) {
                        return true;
                    }
                }
                break;
            case AND:
                List<String> duplicateList = new ArrayList<>();
                // 循环取出相同的元素重新组合
                for (int i = 0; i < roleList.length; i++) {
                    if (ArrayUtils.contains(requiresRoles.value(), roleList[i])) {
                        duplicateList.add(roleList[i]); //相同的元素
                    }
                }
                String[] identicalArr = duplicateList.toArray(new String[duplicateList.size()]);
                // 判断两个数组是否相同
                if (Arrays.equals(requiresRoles.value(), identicalArr)) {
                    return true;
                }
                break;
        }
        return false;
    }

    private HttpServletRequest currentRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return Optional.ofNullable(servletRequestAttributes).map(ServletRequestAttributes::getRequest).orElse(null);
    }
}
